package com.engine.jucailinkq.attendance.attendanceanalysis.service.impl;

import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.item.AbsenteeismItemCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.item.BeLateItemCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.item.LeaveEarlyItemCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.ComprehensiveWorkingHourService;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.UtilService;
import com.engine.jucailinkq.attendance.enums.*;
import com.engine.jucailinkq.common.util.CommonUtil;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.common.util.ServiceUtil;
import com.engine.jucailinkq.common.util.Utils;
import com.engine.core.impl.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import weaver.general.Util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class ComprehensiveWorkingHourServiceImpl extends Service implements ComprehensiveWorkingHourService {
    private UtilService utilService = ServiceUtil.getService(UtilServiceImpl.class);


    @Override
    public Map<String, Object> excuteByWorkHour(Map<String, Object> param) {
        Map<String, Object> resultMap = Maps.newHashMap();

        //按照日期分割的打卡时间
        List<Map<String,Object>> clockInTimeList = (List<Map<String,Object>>) param.get("clockInTimeCollect");
        //分析日期
        String analysisDate = Util.null2String(param.get("analysisDate"));
        //人员
        String userId = Util.null2String(param.get("userId"));
        //考勤项目
        List<Map<String,Object>> attendanceItems = (List<Map<String,Object>>)param.get("attendanceItems");

        //综合工时
        Map<String,Object> workHourItem = (Map<String,Object>)param.get("workHourItem");
        //日工作时长不足，核算异常
        String rgzscbzhsyc= Util.null2String(workHourItem.get("rgzscbzhsyc"));
        //日最晚打卡报到时间
        String rzwdkbdsj = Util.null2String(workHourItem.get("rzwdkbdsj"));
        //日工作时长要求
        double rgzscyq = Double.valueOf(Util.null2String(workHourItem.get("rgzscyq")));
        //累计出勤时长的核算分钟数
        int ljcqscdhsfzs = Integer.valueOf(Util.null2String(workHourItem.get("ljcqscdhsfzs")));
        //超出日工作时长要求，计入出勤 时长
        String ccrgzscyqjrcqsc = Util.null2String(workHourItem.get("ccrgzscyqjrcqsc"));
        //日最长工作时长
        double rzcgzsc = Double.valueOf(Util.null2String(workHourItem.get("rzcgzsc")));
        //核算工时的日期类型
        String hsgsdrqlx = Util.null2String(workHourItem.get("hsgsdrqlx"));


        String cqzt = "0";

        String rqlx = Utils.getDateType(analysisDate,Util.null2String(workHourItem.get("qyrl")));

        if (!CommonUtil.ifContainStr(hsgsdrqlx,rqlx,",")){
            log.debug("userId :[{}],analysisDate :[{}] 综合工时执行的日期不在设置的日期类型内",userId,analysisDate);
            resultMap.put("message","综合工时执行的日期不在设置的日期类型内");
            resultMap.put("excute",false);
            return resultMap;
        }

        //异常项目
        List<Map<String, Object>> recordDataList = Lists.newArrayList();

        clockInTimeList = getClockInDataByRule(param);

        int betweenMinute = getDurationMinute(clockInTimeList);
        if (betweenMinute == 0 || clockInTimeList.size()==0 || clockInTimeList.size()==1){
            if (rgzscbzhsyc.equals(CheckBoxEnum.CHECKED.getKey())){
                //记漏打卡项目
                if (clockInTimeList.size()==0){
                    Map<String, Object> itemMap1 = Maps.newHashMap();
                    itemMap1.put("item", SystemItemEnum.MISSING_CLOCK_IN.getKey());
                    itemMap1.put("itemduration","1");
                    Map<String, Object> itemMap2 = Maps.newHashMap();
                    itemMap2.put("item", SystemItemEnum.MISSING_CLOCK_IN.getKey());
                    itemMap2.put("itemduration","1");
                    recordDataList.add(itemMap1);
                    recordDataList.add(itemMap2);
                }else {
                    Map<String, Object> itemMap = Maps.newHashMap();
                    itemMap.put("item", SystemItemEnum.MISSING_CLOCK_IN.getKey());
                    itemMap.put("itemduration","1");
                    recordDataList.add(itemMap);
                }
            }
        }
        double adjustBetWeenMinute = Utils.getItemdurationDown(ljcqscdhsfzs, AccountingUnitEnum.MINUTES.getKey(),betweenMinute,AccountingUnitEnum.MINUTES);
        double adjustBetweenHour = new BigDecimal(adjustBetWeenMinute).divide(new BigDecimal(60),2, RoundingMode.HALF_UP).doubleValue();
        log.debug("betweenMinute : [{}],adjustBetWeenMinute: [{}],betweenHour:[{}]",betweenMinute,adjustBetWeenMinute,adjustBetweenHour);

        if (clockInTimeList.size() > 1){
            String reportTime = clockInTimeList.get(0).get("signdate")+" "+clockInTimeList.get(0).get("signtime");
            int lateDurationTime = 0;
            int earlyLeaveMinute = 0;
            Map<String,Object> abnormalParams = Maps.newHashMap();
            abnormalParams.put("attendanceItems",attendanceItems);
            abnormalParams.put("rqlx",rqlx);
            abnormalParams.put("workfor", WorkForTimeEnum.WORK_TIME.getKey());
            if (!"".equals(rzwdkbdsj)){
                String lastReportTime = Utils.installTime(analysisDate,rzwdkbdsj);
                if (Utils.dateGreaterThan(reportTime,lastReportTime)){
                    //迟到
                    lateDurationTime = DateUtil.getBetWeenMinutes(lastReportTime,reportTime);
                }
            }
            if ((betweenMinute+lateDurationTime) < (rgzscyq*60)){
                //早退
                earlyLeaveMinute = Double.valueOf(rgzscyq*60-(betweenMinute+lateDurationTime)).intValue();
            }
            log.debug("lateDurationTime : [{}],earlyLeaveMinute:[{}]",lateDurationTime,earlyLeaveMinute);
            if (rgzscbzhsyc.equals(CheckBoxEnum.CHECKED.getKey())){
                if (lateDurationTime > 0){
                    //计入迟到项目
                    abnormalParams.put("time",lateDurationTime);
                    Map<String,Object> result = commandExecutor.execute(new BeLateItemCmd(abnormalParams));
                    List<Map<String,Object>> workTimeBeLateItems = (List<Map<String,Object>>)result.get("attendanceItems");
                    if (workTimeBeLateItems.size() == 0){
                        workTimeBeLateItems = (List<Map<String,Object>>)commandExecutor.execute(new AbsenteeismItemCmd(abnormalParams)).get("attendanceItems");
                    }
                    if (workTimeBeLateItems.size() == 0){
                        workTimeBeLateItems = attendanceItems.stream().filter(e->SystemItemEnum.MISSING_ABSENTEEISM.getKey().equals(e.get("key"))).collect(Collectors.toList());
                    }
                    if (workTimeBeLateItems.size() > 0){
                        double hsl = Double.valueOf(Util.null2String(workTimeBeLateItems.get(0).get("hsl")));
                        String hsdw = Util.null2String(workTimeBeLateItems.get(0).get("hsdw"));
                        double itemduration = Utils.getItemduration(hsl,hsdw,lateDurationTime,AccountingUnitEnum.MINUTES,rgzscyq);
                        Map<String, Object> itemMap = Maps.newHashMap();
                        itemMap.put("item", workTimeBeLateItems.get(0).get("key"));
                        itemMap.put("itemduration",itemduration);
                        recordDataList.add(itemMap);
                    }
                }
                if (earlyLeaveMinute > 0){
                    //计早退项目
                    abnormalParams.put("time",earlyLeaveMinute);
                    Map<String,Object> result = commandExecutor.execute(new LeaveEarlyItemCmd(abnormalParams));
                    List<Map<String,Object>> workTimeBeLateItems = (List<Map<String,Object>>)result.get("attendanceItems");
                    if (workTimeBeLateItems.size() == 0){
                        workTimeBeLateItems = (List<Map<String,Object>>)commandExecutor.execute(new AbsenteeismItemCmd(abnormalParams)).get("attendanceItems");
                    }
                    if (workTimeBeLateItems.size() == 0){
                        workTimeBeLateItems = attendanceItems.stream().filter(e->SystemItemEnum.MISSING_ABSENTEEISM.getKey().equals(e.get("key"))).collect(Collectors.toList());
                    }
                    if (workTimeBeLateItems.size() > 0){
                        double hsl = Double.valueOf(Util.null2String(workTimeBeLateItems.get(0).get("hsl")));
                        String hsdw = Util.null2String(workTimeBeLateItems.get(0).get("hsdw"));
                        double itemduration = Utils.getItemduration(hsl,hsdw,earlyLeaveMinute,AccountingUnitEnum.MINUTES,rgzscyq);
                        Map<String, Object> itemMap = Maps.newHashMap();
                        itemMap.put("item", workTimeBeLateItems.get(0).get("key"));
                        itemMap.put("itemduration",itemduration);
                        recordDataList.add(itemMap);
                    }
                }
            }
        }
        //超出日工作时长要求，计入出勤 时长,否则最大为日工作时长要求
        if (CheckBoxEnum.CHECKED.getKey().equals(ccrgzscyqjrcqsc)){
            if (adjustBetweenHour > rzcgzsc){
                adjustBetweenHour = rzcgzsc;
            }
        }else {
            if (adjustBetweenHour > rgzscyq){
                adjustBetweenHour=rgzscyq;
            }
        }
        if (recordDataList.size() > 0){
            cqzt="1";
        }



        Map<String,Object> recordParam = Maps.newHashMap();
        recordParam.put("userId",userId);
        recordParam.put("analysisDate",analysisDate);
        recordParam.put("recordData",recordDataList);
        recordParam.put("rqlx",rqlx);
        recordParam.put("classInfo",Lists.newArrayList());
        recordParam.put("recordDataTime",getRecordDataTime(clockInTimeList));
        recordParam.put("attendanceDuration",adjustBetweenHour);
        recordParam.put("formmodeIdMap",Utils.getFormmodeIdMap());
        recordParam.put("cqzt",cqzt);

        resultMap.put("recordParam",recordParam);
        utilService.recordItem(recordParam);
        resultMap.put("excute",true);
        return resultMap;
    }

    /**
     * 根据综合工时规则获取打卡时间
     * @param param
     * @return
     */
    public List<Map<String,Object>> getClockInDataByRule(Map<String, Object> param){

        //按照日期分割的打卡时间
        List<Map<String,Object>> clockInTimeList = (List<Map<String,Object>>) param.get("clockInTimeCollect");
        //分析日期
        String analysisDate = Util.null2String(param.get("analysisDate"));
        //综合工时
        Map<String,Object> workHourItem = (Map<String,Object>)param.get("workHourItem");
        //最早打卡上班的开始时间
        String zzdksbdkssj = Util.null2String(workHourItem.get("zzdksbdkssj"))+":00";
        //最晚打卡下班的开始时间
        String zwdkxbdkssj = Util.null2String(workHourItem.get("zwdkxbdkssj"));
        //日工作时长计算规则 0:最早最晚打卡间隔时长,1:依次累加成对打卡间隔时长
        String rgzscjsgz = Util.null2String(workHourItem.get("rgzscjsgz"));
        //调整上班开始到
        String dzsbksd = Util.null2String(workHourItem.get("dzsbksd"));
        //误打卡忽略分钟数
        int wdkhlfzs = Util.null2String(workHourItem.get("yxdkzxjgfzs")).equals("")?1:Integer.valueOf(Util.null2String(workHourItem.get("yxdkzxjgfzs")));
        //当天漏卡延长取第二天打卡
        String dtlkycqdetdk = Util.null2String(workHourItem.get("dtlkycqdetdk"));



        String startTime = analysisDate+" "+zzdksbdkssj;
        String endTime = analysisDate+" "+zwdkxbdkssj+":00";
        if ("".equals(zwdkxbdkssj)){
            endTime = DateUtil.AfterDay(analysisDate,1)+" "+zzdksbdkssj;
            endTime = DateUtil.beforeMinutes(endTime,1);
        }
        if (DateUtil.getTime(startTime).compareTo(DateUtil.getTime(endTime)) >=0){
            endTime = DateUtil.AfterDay(analysisDate,1) +" "+zwdkxbdkssj+":00";
        }

        String finalEndTime = endTime;

        clockInTimeList = clockInTimeList.stream().filter(e -> {
            String signdate = Util.null2String(e.get("signdate"));
            String signtime = Util.null2String(e.get("signtime"));
            String time = signdate +" "+signtime;

            return DateUtil.getTime(startTime).compareTo(DateUtil.getTime(time)) <=0 && DateUtil.getTime(finalEndTime).compareTo(DateUtil.getTime(time)) >=0;
        }).collect(Collectors.toList());

        clockInTimeList = clockInTimeList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

        if (clockInTimeList.size()==1 && dtlkycqdetdk.equals(CheckBoxEnum.CHECKED.getKey())){
            //当天打卡是奇次的，第二天第一笔卡拿过来当当天的下班卡，且第二天的上班从第二笔卡开始
            String nextEndTime = DateUtil.AfterDay(endTime.split(" ")[0],1)+" "+endTime.split(" ")[1];
            String finalEndTime1 = endTime;
            List<Map<String,Object>> nextClockList = ((List<Map<String,Object>>) param.get("clockInTimeCollect")).stream().filter(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).
                            compareTo(DateUtil.getTime(nextEndTime)) <=0 && DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).compareTo(DateUtil.getTime(finalEndTime1)) > 0)
                    .sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
            String lastSignTime = clockInTimeList.get(0).get("signdate")+" "+clockInTimeList.get(0).get("signtime");
            for (Map<String,Object> nextClock:nextClockList){
                String nextSign = nextClock.get("signdate")+" "+nextClock.get("signtime");
                if (DateUtil.getBetWeenMinutes(lastSignTime,nextSign) >=wdkhlfzs){
                    clockInTimeList.add(nextClock);
                    break;
                }
            }
        }
        if (clockInTimeList.size() == 0 || clockInTimeList.size() ==1){
            return clockInTimeList;
        }

        List<Map<String,Object>> newClockInTimeList = Lists.newArrayList();
        if ("0".equals(rgzscjsgz)){
            //最早最晚打卡间隔时长
            newClockInTimeList.add(clockInTimeList.get(0));
            newClockInTimeList.add(clockInTimeList.get(clockInTimeList.size()-1));

        }else if ("1".equals(rgzscjsgz)){
            //依次累加成对打卡间隔时长
            if (clockInTimeList.size() > 1){
                //数据清洗

                for (int i=0;i<clockInTimeList.size()-1;i++){
                    String time1 = clockInTimeList.get(i).get("signdate")+" "+clockInTimeList.get(i).get("signtime");
                    for (int j=i+1;j<clockInTimeList.size();j++){
                        String time2 = clockInTimeList.get(j).get("signdate")+" "+clockInTimeList.get(j).get("signtime");
                        if (DateUtil.getBetWeenMinutes(time1,time2) <wdkhlfzs){
                            clockInTimeList.remove(clockInTimeList.get(j));
                            j--;
                        }
                    }
                }
//                for (Map<String,Object> map:needRemoveData){
//                    clockInTimeList.remove(map);
//                }
            }

            newClockInTimeList = clockInTimeList;

        }
        if (newClockInTimeList.size()%2==1 && dtlkycqdetdk.equals(CheckBoxEnum.CHECKED.getKey())){
            //当天打卡是奇次的，第二天第一笔卡拿过来当当天的下班卡，且第二天的上班从第二笔卡开始
            String nextEndTime = DateUtil.AfterDay(endTime.split(" ")[0],1)+" "+endTime.split(" ")[1];
            String finalEndTime1 = endTime;
            List<Map<String,Object>> nextClockList = ((List<Map<String,Object>>) param.get("clockInTimeCollect")).stream().filter(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).
                            compareTo(DateUtil.getTime(nextEndTime)) <=0 && DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).compareTo(DateUtil.getTime(finalEndTime1)) > 0)
                    .sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
            String lastSignTime = newClockInTimeList.get(newClockInTimeList.size()-1).get("signdate")+" "+newClockInTimeList.get(newClockInTimeList.size()-1).get("signtime");
            for (Map<String,Object> nextClock:nextClockList){
                String nextSign = nextClock.get("signdate")+" "+nextClock.get("signtime");
                if (DateUtil.getBetWeenMinutes(lastSignTime,nextSign) >=wdkhlfzs){
                    newClockInTimeList.add(nextClock);
                    break;
                }
            }
            if (newClockInTimeList.size()%2==1){
                newClockInTimeList.remove(newClockInTimeList.size()-1);
            }

        }

        if (newClockInTimeList.size() > 0){
            String time = newClockInTimeList.get(0).get("signdate")+" "+newClockInTimeList.get(0).get("signtime");
            int minute = DateUtil.getTime(time).getMinute();
            int hour = DateUtil.getTime(time).getHour();
            if ("1".equals(dzsbksd)){
                //整点
                if (minute > 0){
                    hour=hour+1;
                }
                String hourstr = DateUtil.getTimeStr(hour);
                newClockInTimeList.get(0).put("signtime",hourstr+":00");

            }else if ("2".equals(dzsbksd)){
                //半点
                String minuteStr = "";
                if (minute < 30){
                    minuteStr = "30";
                }else if (minute > 30){
                    minuteStr = "00";
                    hour = hour+1;
                }
                String hourstr = DateUtil.getTimeStr(hour);
                newClockInTimeList.get(0).put("signtime",hourstr+":"+minuteStr);

            }else if ("3".equals(dzsbksd)){
                //15分钟
                if (minute%15 > 0){
                    minute = (minute/15)*15+15;
                    if (minute == 60){
                        minute = 0;
                        hour = hour+1;
                    }
                }
                String hourstr = DateUtil.getTimeStr(hour);
                String minutestr = DateUtil.getTimeStr(minute);
                newClockInTimeList.get(0).put("signtime",hourstr+":"+minutestr);
            }
            if (newClockInTimeList.size() > 1){
                String firstSignDate = newClockInTimeList.get(0).get("signdate")+" "+newClockInTimeList.get(0).get("signtime");
                String twoSignDate = newClockInTimeList.get(1).get("signdate")+" "+newClockInTimeList.get(1).get("signtime");
                //当调整后第一笔上班时间超过第二比那么去除这2比记录
                if (DateUtil.getTime(firstSignDate).compareTo(DateUtil.getTime(twoSignDate)) >=0){
                    newClockInTimeList.remove(0);
                    newClockInTimeList.remove(0);
                }
            }

        }


        log.debug("newClockInTimeList : [{}]",newClockInTimeList);
        return newClockInTimeList;
    }

    /**
     * 获得打卡时间两两直接的时间
     * @param clockInTimeList 打卡时间
     * @return 分钟数
     */
    public int getDurationMinute(List<Map<String,Object>> clockInTimeList){
        if (clockInTimeList.size() == 0){
            return 0;
        }
        int logarithm = clockInTimeList.size()/2;
        int betweenMinute = 0;
        for (int i =0;i<logarithm;i++){
            int index1 = i*2;
            int index2 = index1+1;
            String time1 = clockInTimeList.get(index1).get("signdate") +" "+clockInTimeList.get(index1).get("signtime");
            String time2 = clockInTimeList.get(index2).get("signdate") +" "+clockInTimeList.get(index2).get("signtime");
            betweenMinute += DateUtil.getBetWeenMinutes(time1,time2);
        }
        log.debug("betweenMinute : [{}]",betweenMinute);
        return betweenMinute;
    }

    /**
     * 获得进出时间
     * @param clockInTimeList
     * @return
     */
    public Map<String,Object> getRecordDataTime(List<Map<String,Object>> clockInTimeList){
        Map<String,Object> resultMap = Maps.newHashMap();
        if (clockInTimeList.size() == 0 ){

        }else if (clockInTimeList.size() == 1){
            resultMap.put("j1",clockInTimeList.get(0).get("signdate")+" "+clockInTimeList.get(0).get("signtime"));

        }
        int logarithm = clockInTimeList.size()/2;

        for (int i =0;i<logarithm;i++){
            int index1 = i*2;
            int index2 = index1+1;
            resultMap.put("j"+(i+1),clockInTimeList.get(index1).get("signdate")+" "+clockInTimeList.get(index1).get("signtime"));
            resultMap.put("c"+(i+1),clockInTimeList.get(index2).get("signdate")+" "+clockInTimeList.get(index2).get("signtime"));
        }
        for (int i=1;i<=8;i++){
            String jkey = "j"+i;
            String ckey = "c"+i;
            if (resultMap.get(jkey) == null){
                resultMap.put(jkey,"NULL");
            }
            if (resultMap.get(ckey) == null){
                resultMap.put(ckey,"NULL");
            }
        }
        log.debug("betweenMinute : [{}]",resultMap);
        return resultMap;
    }
}
